<?php
// workerman启动

use think\Middleware;
use think\Route;
use Workerman\Worker;
use Workerman\Protocols\Http;
use Workerman\Connection\TcpConnection;
use support\bootstrap\Log;
use support\bootstrap\Container;
use teamones\tracker\TeamonesApp as App;
use think\Request;

require_once __DIR__ . '/vendor/autoload.php';

// 定义应用目录
define('APP_PATH', __DIR__ . '/app/');

// 注册自动加载
think\Loader::register();

// 注册错误和异常处理机制
think\Error::register();

// 设置默认时区
if ($timezone = C('DEFAULT_TIMEZONE_SET')) {
    date_default_timezone_set($timezone);
}

// server 配置
$serverConfig = C('server');

// 检测数据结构是否正确
try {
    // 自动执行migrate操作
    // 只在生产环境自动执行 开发环境不自动执行 避免未写完的migrate 自动执行到开发环境
    if (class_exists('Phinx\Migration\Manager') && !C("app_debug")) {
        exec("vendor/robmorgan/phinx/bin/phinx migrate", $output);
        echo "Database Migration " . $output[count($output) - 1] . PHP_EOL;
    }

    \think\module\Module::checkSchema();

} catch (\RuntimeException $e) {
    echo $e->getMessage() . PHP_EOL;
    exit();// 终止运行
}

// 拉起etcd服务
if (class_exists('teamones\process\EtcdGoServer')) {
    \teamones\process\EtcdGoServer::exec();

    // Workerman 关闭杀死 etcd服务
    worker::$onMasterStop = function () {
        \teamones\process\EtcdGoServer::kill();
    };
}

// 自动上报注册路由
$routeRegisterConfig = config('route_register', []);
$ruleConfig = [];
if (!empty($routeRegisterConfig)) {
    $files = C('ROUTE_CONFIG_FILE');
    $enforcer = new teamones\registerRoute\Enforcer($routeRegisterConfig['url']);
    foreach ($files as $file) {
        if (is_file(COMMON_PATH . 'config/' . $file . CONF_EXT)) {
            // 导入路由配置
            $rules = include COMMON_PATH . 'config/' . $file . CONF_EXT;
            if (is_array($rules)) {
                $ruleConfig[] = $rules;
                $enforcer->registerTeamonesFramework($rules, config('belong_system'));
            }
        }
    }
}

// Workerman 重启清空 opcache
Worker::$onMasterReload = function () {
    if (function_exists('opcache_get_status')) {
        if ($status = opcache_get_status()) {
            if (isset($status['scripts']) && $scripts = $status['scripts']) {
                foreach (array_keys($scripts) as $file) {
                    opcache_invalidate($file, true);
                }
            }
        }
    }
};

Worker::$pidFile = $serverConfig['pid_file'];
Worker::$stdoutFile = $serverConfig['stdout_file'];
Worker::$logFile = $serverConfig['log_file'];
TcpConnection::$defaultMaxPackageSize = $serverConfig['max_package_size'] ?? 10 * 1024 * 1024;

$worker = new Worker($serverConfig['listen'], $serverConfig['context']);
$propertyMap = [
    'name',
    'count',
    'user',
    'group',
    'reusePort',
    'transport',
];
foreach ($propertyMap as $property) {
    if (isset($serverConfig[$property])) {
        $worker->$property = $serverConfig[$property];
    }
}

$worker->onWorkerStart = function ($worker) use ($ruleConfig) {
    set_error_handler(function ($level, $message, $file = '', $line = 0, $context = []) {
        if (error_reporting() & $level) {
            throw new ErrorException($message, 0, $level, $file, $line);
        }
    });
    register_shutdown_function(function ($start_time) {
        if (time() - $start_time <= 1) {
            sleep(1);
        }
    }, time());

    foreach (C('bootstrap') as $class) {
        /** @var \think\Bootstrap $class_name */
        $class::start($worker);
    }


    $worker->onMessage = function ($connection, $data) {
        $connection->send('receive success');
    };

    \think\module\Module::init();

    $app = new App($worker, Container::instance(), Log::channel('default'), app_path(), public_path());

    // 初始化路由
    foreach ($ruleConfig as $rules) {
        Route::import($rules);
    }

    Middleware::load(C('middleware'));
    Http::requestClass(Request::class);

    $worker->onMessage = [$app, 'onMessage'];
};

// 启动自定义进程
foreach (C('process') as $process_name => $config) {
    $worker = new Worker($config['listen'] ?? null, $config['context'] ?? []);
    $property_map = [
        'count',
        'user',
        'group',
        'reloadable',
        'reusePort',
        'transport',
        'protocol',
    ];
    $worker->name = $process_name;
    foreach ($property_map as $property) {
        if (isset($config[$property])) {
            $worker->$property = $config[$property];
        }
    }

    $worker->onWorkerStart = function ($worker) use ($config) {
        foreach (C('bootstrap') as $class) {
            /** @var \think\Bootstrap $class_name */
            $class::start($worker);
        }

        \think\module\Module::init();

        // 初始化RPC Request 对象
        \think\Rpc::instanceRequest();

        foreach ($config['services'] ?? [] as $server) {
            if (!class_exists($server['handler'])) {
                echo "process error: class {$config['handler']} not exists\r\n";
                continue;
            }
            $listen = new Worker($server['listen'] ?? null, $server['context'] ?? []);
            if (isset($server['listen'])) {
                echo "listen: {$server['listen']}\n";
            }
            $class = Container::make($server['handler'], $server['constructor'] ?? []);
            worker_bind($listen, $class);
            $listen->listen();
        }

        if (isset($config['handler'])) {
            if (!class_exists($config['handler'])) {
                echo "process error: class {$config['handler']} not exists\r\n";
                return;
            }

            $class = Container::make($config['handler'], $config['constructor'] ?? []);
            worker_bind($worker, $class);
        }

    };
}

Worker::runAll();
